package com.xyzwps.server.paimon.app

import com.xyzwps.server.paimon.app.dto.ArticleCreateInput
import com.xyzwps.server.paimon.app.dto.ArticlesGetInput
import com.xyzwps.server.paimon.app.dto.ArticleUpdateInput
import com.xyzwps.server.paimon.app.filter.AppFilter
import com.xyzwps.server.paimon.app.filter.AppFilterToken.AUTH
import com.xyzwps.server.paimon.common.CursorPage
import com.xyzwps.server.paimon.error.Errors
import com.xyzwps.server.paimon.common.Utils.uuid4
import com.xyzwps.server.paimon.ext.instantNow
import com.xyzwps.server.paimon.model.entity.Article
import com.xyzwps.server.paimon.model.service.ArticleDomainService
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class ArticleAppService(
    private val articleDomainService: ArticleDomainService
) {

    // TODO: 增加数据格式检查
    @AppFilter([AUTH])
    fun create(user: ContextUser, input: ArticleCreateInput): String = transaction {
        val newArticle = Article(
            // TODO: 去重
            id = null,
            uid = uuid4().toString(), // TODO: uid 用来做什么？
            userId = user.id,
            title = input.title,
            content = input.content,
            createdAt = instantNow()
        )
        articleDomainService.save(newArticle)
        newArticle.uid
    }

    @AppFilter([AUTH])
    @Transactional
    fun update(user: ContextUser, uid: String, input: ArticleUpdateInput): String = transaction {
        val userId = user.id
        val article = articleDomainService.getByUidAndUserId(uid, userId) ?: throw Errors.ARTICLE_NOT_FOUND.toEx()
        val newArticle = article.copy(title = input.title, content = input.content)
        articleDomainService.save(newArticle)
        newArticle.uid
    }

    fun get(uid: String): Article = transaction {
        articleDomainService.getByUid(uid) ?: throw Errors.ARTICLE_NOT_FOUND.toEx()
    }

    @AppFilter([AUTH])
    fun get(user: ContextUser, input: ArticlesGetInput): CursorPage<Article, String?> = transaction {
        val limit = input.count
        val uid = input.cursor
        var beforeId: Long? = null
        if (uid != null) {
            // TODO: 这个可以做的更好，因为 cursor 对应的这个可能已经被删了，会导致 404
            beforeId = articleDomainService.getByUidAndUserId(uid, user.id)?.id
                ?: throw Errors.ARTICLE_NOT_FOUND.toEx()
        }

        val queryCount = limit + 1
        val articles = articleDomainService.getBefore(beforeId, user.id, queryCount)
        val hasMore = articles.size > limit
        val items = articles.take(kotlin.math.min(limit, articles.size))
        val nextCursor = if (hasMore) items.last().uid else null
        CursorPage(items, nextCursor, hasMore)
    }
}
